package com.yanqu.road.server.manger.activity.tripletown;

import com.yanqu.road.entity.activity.tripletown.*;
import com.yanqu.road.entity.activity.tripletown.config.IConfig;
import com.yanqu.road.entity.activity.tripletown.config.IOrderConfig;
import com.yanqu.road.entity.activity.tripletown.config.IScoreConfig;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 三消-逻辑
 */
public class EliminateLogic {

    public static final Logger logger = LogManager.getLogger(EliminateLogic.class.getName());

    /**
     * 消除
     *
     * @param fromX 从这里
     * @param toX   跟这里交换
     */
    public static EliminateResult eliminateBlock(IConfig config,
            IUserData userData, int multi, int fromX, int fromY, int toX, int toY) {

        Random random = new Random();

        // 一堆数据
        EliminateResult result = new EliminateResult(); // 最终结果
        int guideIndex = userData.getGuideIndex(); // 引导下标
        int[][] copyBlockList = getCopyBlockList(userData.getBlockList(multi)); // 复制的全部格子

        Map<Integer, Map<Integer, Block>> dropMap = new ConcurrentHashMap<>(); // 上一轮掉落的方块
        for (int tmpY = 0; tmpY < copyBlockList.length; tmpY++) dropMap.put(tmpY, new ConcurrentHashMap<>());

        // 【校验】
        if (!(Math.abs(fromX - toX) == 1 && fromY == toY || Math.abs(fromY - toY) == 1 && fromX == toX)) {
            result.setRet(GameErrorCode.E_REQUEST_ARGUMENT_ERROR);
            return result;
        }

        // 【交换】
        exchangeBlock(copyBlockList, fromX, fromY, toX, toY);

        // 【订单】
        Order copyOrder = getCopyOrder(userData.getOrder(multi)); // 复制的订单
        if(copyOrder != null){
            copyOrder.setStep(copyOrder.getStep() + 1);
        }

        // 【循环处理每轮数据】
        for (int round = 1; round <= 100; round++) {

            // 又是一堆数据
            EliminateRoundResult roundResult = new EliminateRoundResult(); // 每轮结果
            Map<Integer, Map<Integer, Block>> eliminateMap = new ConcurrentHashMap<>(); // 记录消除的格子
            for (int y = 0; y < copyBlockList.length; y++) eliminateMap.put(y, new ConcurrentHashMap<>());

            // 【分阶段标记消除的方块】
            if (round == 1) { // 首轮有炸弹连环爆炸，有多阶段
                List<Block> waitBoomList = new ArrayList<>();
                for (int stage = 1; stage <= 100; stage++) { // 假装是while
                    EliminateStageResult stageResult = new EliminateStageResult();
                    if (stage == 1) {
                        handleFirstBomb(copyBlockList, eliminateMap, fromX, fromY, toX, toY, stageResult, waitBoomList); // 首次炸弹
                        handleEliminateX(copyBlockList, eliminateMap, stageResult); // 横向
                        handleEliminateY(copyBlockList, eliminateMap, stageResult); // 纵向
                    } else {
                        waitBoomList = handleBombBoom(copyBlockList, eliminateMap, stageResult, waitBoomList); // 其他次炸弹
                    }
                    roundResult.getStageResultList().add(stageResult);
                    // 判断连环炸弹全部爆炸完
                    if (waitBoomList.isEmpty()) break;
                }
            } else { // 其他轮只有消除，一阶段
                EliminateStageResult stageResult = new EliminateStageResult();
                handleEliminateX(copyBlockList, eliminateMap, stageResult); // 横向
                handleEliminateY(copyBlockList, eliminateMap, stageResult); // 纵向
                roundResult.getStageResultList().add(stageResult);
            }

            // 【判断是否结束】
            if (!hadEliminate(eliminateMap)) {
                if (round == 1) {
                    result.setRet(GameErrorCode.E_LANRUOSI_ACTIVITY_NO_BLOCK_TO_ELIMINATE);
                    return result;
                } else {
                    break; // 如果没失败，后续还有操作，不能return
                }
            }

            // 【消除方块】
            setEliminateEmpty(copyBlockList, round, multi, eliminateMap, config);

            // 【加炸弹】
            AddBombLogic.addBomb(fromX, fromY, toX, toY, round, eliminateMap, dropMap, copyBlockList, roundResult);

            // 【订单】
            if(copyOrder != null) {

                // 【加订单进度】
                addOrderProg(copyOrder, eliminateMap);

                // 【设置当前订单】
                roundResult.setCurOrder(getCopyOrder(copyOrder));
            }

            // 【填充方块】
            dropMap = new ConcurrentHashMap<>(); // 记录掉落方块
            for (int tmpY = 0; tmpY < copyBlockList.length; tmpY++) dropMap.put(tmpY, new ConcurrentHashMap<>());
            dropOldBlock(copyBlockList, dropMap); //旧方块掉落
            guideIndex = dropNewBlock(multi, guideIndex, copyBlockList, dropMap, config); // 添加新方块

            // 【添加本轮结果】
            roundResult.setBlockList(getCopyBlockList(copyBlockList));
            result.getRoundResultList().add(roundResult);

            // 【判断死局】
            if (!calEliminateTips(copyBlockList).isSuccess()) {
                for (int i = 0; i < 10; i++) { // 重排到可以消除才结束
                    rearrange(copyBlockList);
                    if (calEliminateTips(copyBlockList).isSuccess()) {
                        break;
                    }
                }
                // 【添加重排结果】
                EliminateRoundResult tmpRoundResult = new EliminateRoundResult();
                tmpRoundResult.setBlockList(getCopyBlockList(copyBlockList));
                tmpRoundResult.setType(2); // 1正常消除，2重排
                // 【订单】
                if(copyOrder != null) {
                    tmpRoundResult.setCurOrder(getCopyOrder(copyOrder));
                }
                result.getRoundResultList().add(tmpRoundResult);
            }

        }

        // 【处理订单】
        handleOrder(config, userData, multi, random, result, copyBlockList, copyOrder);

        // 【最终数据】
        result.setGuideIndex(guideIndex);

        return result;
    }

    private static void handleOrder(IConfig config, IUserData userData, int multi, Random random, EliminateResult result, int[][] copyBlockList, Order copyOrder) {
        List<Integer> orderIdList = userData.getOrderIdList(multi);
        if(orderIdList == null || orderIdList.size() == 0){
            return;
        }
        List<Integer> copyOrderIdList = new ArrayList<>(orderIdList);
        if(copyOrder != null && copyOrderIdList != null && !copyOrderIdList.isEmpty()) {
            // 【最后一轮数据的订单  完成/失败  处理】
            int orderStatus = checkOrderStatus(copyOrder);
            if (orderStatus == 2) { // 完成
                EliminateRoundResult roundResult = result.getRoundResultList().get(result.getRoundResultList().size() - 1);
                // 加炸弹
                if (addOrderBomb(random, copyBlockList, copyOrder, roundResult, config)) {
                    // 本轮结果重新设置方块
                    roundResult.setBlockList(getCopyBlockList(copyBlockList));
                }
                // 切换下个订单
                roundResult.setFinishOrder(getCopyOrder(copyOrder));
                checkOrderIdList(copyOrderIdList, multi, config); // 先检查下列表比较稳
                copyOrder = createOrder(copyOrderIdList.remove(0), config);
                roundResult.setCurOrder(getCopyOrder(copyOrder));
                // 后续订单
                int orderId = getRandomOrderId(multi, config);
                copyOrderIdList.add(orderId);
                roundResult.setAddOrderId(orderId);
            } else if (orderStatus == 3) { // 失败
                EliminateRoundResult roundResult = result.getRoundResultList().get(result.getRoundResultList().size() - 1);
                // 切换下个订单
                roundResult.setFailOrder(getCopyOrder(copyOrder));
                checkOrderIdList(copyOrderIdList, multi, config); // 先检查下列表比较稳
                copyOrder = createOrder(copyOrderIdList.remove(0), config);
                roundResult.setCurOrder(getCopyOrder(copyOrder));
                // 后续订单
                int orderId = getRandomOrderId(multi, config);
                copyOrderIdList.add(orderId);
                roundResult.setAddOrderId(orderId);
            }
            result.setCurOrder(getCopyOrder(copyOrder));
            result.setOrderIdList(new ArrayList<>(copyOrderIdList));
        }
    }

    /**
     * 掉落新格子
     */
    private static int dropNewBlock(int multi, int guideIndex, int[][] copyBlockList, Map<Integer, Map<Integer, Block>> dropMap, IConfig config) {
        // 计算权重
        Map<Integer, Integer> countMap = new ConcurrentHashMap<>();
        int startNum = multi == 16 ? 11 : multi == 8 ? 5 : 1;
        for (int i = 0; i <= 3; i++)
            countMap.put(startNum + i, 0);
        for (int y = 0; y < copyBlockList.length; y++)
            for (int x = 0; x < copyBlockList[y].length; x++)
                if (countMap.containsKey(copyBlockList[y][x]))
                    countMap.put(copyBlockList[y][x], countMap.get(copyBlockList[y][x]) + 1);
        List<Integer> colorList = new ArrayList<>();
        List<Integer> countList = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
            colorList.add(entry.getKey());
            countList.add(entry.getValue());
        }
        for (int i = 0; i < colorList.size() - 1; i++) {
            for (int j = i + 1; j < colorList.size(); j++) {
                if (countList.get(i) < countList.get(j)) {
                    int tmpColor = colorList.get(i);
                    colorList.set(i, colorList.get(j));
                    colorList.set(j, tmpColor);
                    int tmpCount = countList.get(i);
                    countList.set(i, countList.get(j));
                    countList.set(j, tmpCount);
                }
            }
        }
        int count = -1;
        int rank = -1;
        List<Integer> weightList = new ArrayList<>();
        for (int i = 0; i < colorList.size(); i++) {
            if (count != countList.get(i)) {
                rank++;
                count = countList.get(i);
            }
            int baseWeight = config.getBlockConfigMap().get(colorList.get(i)).getWeight();
            weightList.add(baseWeight + config.getBlockWeightList().get(rank));
        }

        // 获取引导格子
        int[] initBlock = config.getInitBlock();
        // 生成新格子
        Random random = new Random();
        for (int y = 0; y < copyBlockList.length; y++) {
            for (int x = 0; x < copyBlockList[y].length; x++) {
                if (copyBlockList[y][x] == 0) {
                    int block = multi == 1 && guideIndex < initBlock.length ?
                            initBlock[guideIndex++] : calNextBlock(colorList, weightList, random);
                    copyBlockList[y][x] = block;
                    dropMap.get(y).put(x, new Block(x, y, block));
                }
            }
        }
        return guideIndex;
    }

    /**
     * 旧方块掉落
     */
    private static void dropOldBlock(int[][] copyBlockList, Map<Integer, Map<Integer, Block>> dropMap) {
        for (int y = 0; y < copyBlockList.length; y++) {
            for (int x = 0; x < copyBlockList[y].length; x++) {
                if (copyBlockList[y][x] == 0) {
                    int index = -1;
                    for (int tmpY = y + 1; tmpY < copyBlockList.length; tmpY++) {
                        if (copyBlockList[tmpY][x] != 0) {
                            index = tmpY;
                            break;
                        }
                    }
                    if (index != -1) {
                        copyBlockList[y][x] = copyBlockList[index][x];
                        copyBlockList[index][x] = 0;

                        dropMap.get(y).put(x, new Block(x, y, copyBlockList[y][x]));
                    }
                }
            }
        }
    }

    /**
     * 是否有消除
     */
    private static boolean hadEliminate(Map<Integer, Map<Integer, Block>> eliminateMap) {
        boolean haveEliminate = false;
        for (Map<Integer, Block> blockMap : eliminateMap.values()) {
            if (blockMap.size() > 0) {
                haveEliminate = true;
                break;
            }
        }
        return haveEliminate;
    }

    /**
     * 添加任务进度
     */
    private static void addOrderProg(Order copyOrder, Map<Integer, Map<Integer, Block>> eliminateMap) {
        for (Map<Integer, Block> blockMap : eliminateMap.values()) {
            for (Block block : blockMap.values()) {
                OrderProg orderProg = copyOrder.getProgMap().get(block.getC());
                if (orderProg != null) {
                    orderProg.setCur(orderProg.getCur() + 1);
                }
            }
        }
    }

    /**
     * 添加订单炸弹
     */
    private static boolean addOrderBomb(Random random, int[][] copyBlockList, Order copyOrder, EliminateRoundResult roundResult, IConfig config) {
        IOrderConfig orderConfig = config.getOrderConfigMap().get(copyOrder.getoId());
        if (!orderConfig.getSpecParam().equals("0")) {
            int bombType = Integer.valueOf(orderConfig.getSpecParam());
            if (bombType != 0) {
                // 有炸弹
                int blockCount = copyBlockList.length * copyBlockList[0].length;
                int index = random.nextInt(blockCount);
                for (int b = 0; b < blockCount; b++) {
                    int tmpX = (index + b) % blockCount % copyBlockList[0].length;
                    int tmpY = (index + b) % blockCount / copyBlockList[0].length;
                    // 坐标存在，不为空，不是炸弹
                    if (isXyExist(copyBlockList, tmpX, tmpY) && copyBlockList[tmpY][tmpX] != 0 && !isBomb(copyBlockList[tmpY][tmpX])) {
                        // 添加炸弹
                        copyBlockList[tmpY][tmpX] = bombType;
                        // 记录本轮结果
                        roundResult.setOrderBomb(new Block(tmpX, tmpY, bombType));
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取下一个格子
     */
    private static int calNextBlock(List<Integer> colorList, List<Integer> weightList, Random random) {
        int index = RandomHelper.getRandomIndexByWeight(weightList, random);
        return colorList.get(index);
    }

    /**
     * 消除的方块清空
     */
    private static void setEliminateEmpty(int[][] copyBlockList, int round, int multi,
                                          Map<Integer, Map<Integer, Block>> eliminateMap, IConfig config) {
        long blockScore = calBlockScore(round, multi, config);
        for (Map<Integer, Block> blockMap : eliminateMap.values()) {
            for (Block block : blockMap.values()) {
                copyBlockList[block.getY()][block.getX()] = 0;
                // 记录本轮结果
                block.setScore(blockScore);
            }
        }
    }

    /**
     * 处理炸弹爆炸
     *
     * @return 下阶段爆炸的炸弹
     */
    private static List<Block> handleBombBoom(int[][] copyBlockList,
                                                   Map<Integer, Map<Integer, Block>> eliminateMap, EliminateStageResult stageResult,
                                                   List<Block> bombList) {
        List<Block> waitBoomList = new ArrayList<>();
        for (Block bomb : bombList) {
            stageResult.getBoomList().add(new Boom(bomb.getX(), bomb.getY(), bomb.getC() == 9 ? 2 : 1));
            List<Block> blockList = calBoomEliminateList(copyBlockList, bomb.getX(), bomb.getY(), bomb.getC() == 9 ? 2 : 1);
            for (Block Block : blockList) {
                if (!eliminateMap.get(Block.getY()).containsKey(Block.getX())) {
                    eliminateMap.get(Block.getY()).put(Block.getX(), Block);
                    stageResult.getBlockList().add(Block);
                    if (isBomb(Block.getC())) {
                        waitBoomList.add(Block);
                    }
                }
            }
        }
        return waitBoomList;
    }

    /**
     * 处理横向消除
     */
    private static void handleEliminateY(int[][] copyBlockList,
                                         Map<Integer, Map<Integer, Block>> eliminateMap, EliminateStageResult stageResult) {
        for (int x = 0; x < copyBlockList[0].length; x++) {
            for (int y = 0; y < copyBlockList.length - 2; y++) {
                // 不是炸弹 且 能消除
                if (!isBomb(copyBlockList[y][x]) && copyBlockList[y][x] == copyBlockList[y + 1][x] && copyBlockList[y][x] == copyBlockList[y + 2][x]) {
                    int size = 0;
                    for (int tmpY = y; tmpY < copyBlockList.length; tmpY++) {
                        if (copyBlockList[tmpY][x] == copyBlockList[y][x]) {
                            size++;
                            if (!eliminateMap.get(tmpY).containsKey(x)) {
                                Block Block = new Block(x, tmpY, copyBlockList[tmpY][x]);
                                eliminateMap.get(tmpY).put(x, Block);
                                stageResult.getBlockList().add(Block);
                            }
                            eliminateMap.get(tmpY).get(x).setEliminate(true);
                        } else break;
                    }
                    y += size - 1;
                }
            }
        }
    }

    /**
     * 处理横向消除
     */
    private static void handleEliminateX(int[][] copyBlockList,
                                         Map<Integer, Map<Integer, Block>> eliminateMap, EliminateStageResult stageResult) {
        for (int y = 0; y < copyBlockList.length; y++) {
            for (int x = 0; x < copyBlockList[y].length - 2; x++) {
                // 不是炸弹 且 能消除
                if (!isBomb(copyBlockList[y][x]) && copyBlockList[y][x] == copyBlockList[y][x + 1] && copyBlockList[y][x] == copyBlockList[y][x + 2]) {
                    int size = 0;
                    for (int tmpX = x; tmpX < copyBlockList[y].length; tmpX++) {
                        if (copyBlockList[y][tmpX] == copyBlockList[y][x]) {
                            size++;
                            if (!eliminateMap.get(y).containsKey(tmpX)) {
                                Block Block = new Block(tmpX, y, copyBlockList[y][x]);
                                eliminateMap.get(Block.getY()).put(Block.getX(), Block);
                                stageResult.getBlockList().add(Block);
                            }
                            eliminateMap.get(y).get(tmpX).setEliminate(true);
                        } else break;
                    }
                    x += size - 1;
                }
            }
        }
    }

    /**
     * 处理第一次移动的炸弹
     */
    private static void handleFirstBomb(
            int[][] copyBlockList, Map<Integer, Map<Integer, Block>> eliminateMap,
            int fromX, int fromY, int toX, int toY,
            EliminateStageResult stageResult, List<Block> waitBoomList) {

        int type = 0; // 炸弹类型
        int x = -1; // 爆炸中心
        int y = -1; // 爆炸中心

        // 判断首次炸弹爆炸
        if (isBomb(copyBlockList[fromY][fromX]) && isBomb(copyBlockList[toY][toX])) {
            if (copyBlockList[fromY][fromX] == 9 && copyBlockList[toY][toX] == 9) { // 九宫格炸弹 * 2
                x = toX;
                y = toY;
                type = 6;
            } else if (copyBlockList[fromY][fromX] == 9 && copyBlockList[toY][toX] == 10 ||
                    copyBlockList[fromY][fromX] == 10 && copyBlockList[toY][toX] == 9) { // 九宫格炸弹 && 十字炸弹
                y = toY;
                x = toX;
                type = fromY == toY ? 3 : 4;
            } else if (copyBlockList[fromY][fromX] == 10 && copyBlockList[toY][toX] == 10) { // 十字炸弹 * 2
                x = toX;
                y = toY;
                type = 5;
            }
        } else {
            // 普通炸弹
            if (isBomb(copyBlockList[fromY][fromX])) {
                x = fromX;
                y = fromY;
                type = copyBlockList[fromY][fromX] == 9 ? 2 : 1;
            } else if (isBomb(copyBlockList[toY][toX])) {
                x = toX;
                y = toY;
                type = copyBlockList[toY][toX] == 9 ? 2 : 1;
            }
        }

        // 爆炸
        if (type != 0) {
            List<Block> blockList = calBoomEliminateList(copyBlockList, x, y, type);
            for (Block Block : blockList) {
                // 记录消除的格子
                if (!eliminateMap.get(Block.getY()).containsKey(Block.getX())) {
                    eliminateMap.get(Block.getY()).put(Block.getX(), Block);
                    // 记录等会儿要爆炸的格子（要排除掉自身）
                    if (isBomb(Block.getC()) &&
                            !(Block.getY() == fromY && Block.getX() == fromX ||
                                    Block.getY() == toY && Block.getX() == toX)) {
                        waitBoomList.add(Block);
                    }
                    // 记录阶段数据
                    stageResult.getBlockList().add(Block);
                }
            }
            stageResult.getBoomList().add(new Boom(x, y, type));
        }
    }

    /**
     * 计算爆炸消除的点（这里没过滤，可能重复）
     *
     * @param type 爆炸范围类型：0无，1十字，2九宫格，3横三竖一，4横一竖三，5横三竖三，6二十五宫格
     */
    private static List<Block> calBoomEliminateList(int[][] blockList, int stopX, int stopY, int type) {
        List<Block> list = new ArrayList<>();
        if (type == 1) {
            // 十字
            for (int x = 0; x < blockList[stopY].length; x++)
                list.add(new Block(x, stopY, blockList[stopY][x]));
            for (int y = 0; y < blockList.length; y++) list.add(new Block(stopX, y, blockList[y][stopX]));
        } else if (type == 2) {
            // 九宫格
            for (int y = stopY - 1; y <= stopY + 1; y++)
                for (int x = stopX - 1; x <= stopX + 1; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
        } else if (type == 3) {
            // 横三竖一
            for (int y = stopY - 1; y <= stopY + 1; y++)
                for (int x = 0; x < blockList[0].length; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
            for (int y = 0; y < blockList.length; y++) list.add(new Block(stopX, y, blockList[y][stopX]));
        } else if (type == 4) {
            // 横一竖三
            for (int x = 0; x < blockList[stopY].length; x++)
                list.add(new Block(x, stopY, blockList[stopY][x]));
            for (int y = 0; y < blockList.length; y++)
                for (int x = stopX - 1; x <= stopX + 1; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
        } else if (type == 5) {
            // 横三竖三
            for (int y = stopY - 1; y <= stopY + 1; y++)
                for (int x = 0; x < blockList[0].length; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
            for (int y = 0; y < blockList.length; y++)
                for (int x = stopX - 1; x <= stopX + 1; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
        } else if (type == 6) {
            // 二十五宫格
            for (int y = stopY - 2; y <= stopY + 2; y++)
                for (int x = stopX - 2; x <= stopX + 2; x++)
                    if (isXyExist(blockList, x, y)) list.add(new Block(x, y, blockList[y][x]));
        }
        return list;
    }

    /**
     * 是否为炸弹
     */
    public static boolean isBomb(int color) {
        return color == 9 || color == 10;
    }

    /**
     * 交换方块
     */
    private static void exchangeBlock(int[][] blockList, int x1, int y1, int x2, int y2) {
        int tmp = blockList[y1][x1];
        blockList[y1][x1] = blockList[y2][x2];
        blockList[y2][x2] = tmp;
    }

    /**
     * 获取消除提示
     */
    public static EliminateTips calEliminateTips(int[][] blockList) {

        EliminateTips result = new EliminateTips();

        // 先判断道具
        for (int y = 0; y < blockList.length; y++) {
            for (int x = 0; x < blockList[y].length; x++) {
                if (isBomb(blockList[y][x])) {
                    result.setFrom(new Block(x, y, blockList[y][x]));
                    return result;
                }
            }
        }

        // 判断消除
        int[][] copyBlockList = getCopyBlockList(blockList);
        for (int y = 0; y < blockList.length; y++) {
            for (int x = 0; x < blockList[y].length; x++) {
                int stopX;
                int stopY;
                // 向右交换
                stopX = x + 1;
                stopY = y;
                if (tryExchange(blockList, result, copyBlockList, y, x, stopX, stopY))
                    return result;
                // 向左交换
                stopX = x - 1;
                stopY = y;
                if (tryExchange(blockList, result, copyBlockList, y, x, stopX, stopY))
                    return result;
                // 向上交换
                stopX = x;
                stopY = y + 1;
                if (tryExchange(blockList, result, copyBlockList, y, x, stopX, stopY))
                    return result;
                // 向下交换
                stopX = x;
                stopY = y - 1;
                if (tryExchange(blockList, result, copyBlockList, y, x, stopX, stopY))
                    return result;
            }
        }
        result.setSuccess(false);
        return result;
    }

    private static boolean tryExchange(int[][] blockList, EliminateTips result, int[][] copyBlockList, int y, int x, int stopX, int stopY) {
        List<Block> eliminateList;
        if (isXyExist(copyBlockList, x, y) && isXyExist(copyBlockList, stopX, stopY)) {
            exchangeBlock(copyBlockList, x, y, stopX, stopY);
            eliminateList = getEliminateList(copyBlockList, stopX, stopY);
            exchangeBlock(copyBlockList, x, y, stopX, stopY);
            if (eliminateList.size() >= 2) {
                for (Block block : eliminateList) {
                    if (block.getX() == x && block.getY() == y) {
                        eliminateList.remove(block);
                        break;
                    }
                }
                result.setBlockList(eliminateList);
                result.setFrom(new Block(x, y, blockList[y][x]));
                result.setTo(new Block(stopX, stopY, blockList[stopY][stopX]));
                return true;
            }
        }
        return false;
    }

    /**
     * 获取该点一起消除的List（不含该点）
     */
    private static List<Block> getEliminateList(int[][] copyBlockList, int stopX, int stopY) {
        List<Block> xList = new ArrayList<>();
        List<Block> yList = new ArrayList<>();
        for (int tmpX = stopX + 1; tmpX < copyBlockList[0].length; tmpX++) {
            if (copyBlockList[stopY][tmpX] == copyBlockList[stopY][stopX]) {
                xList.add(new Block(tmpX, stopY, copyBlockList[stopY][tmpX]));
            } else {
                break;
            }
        }
        for (int tmpX = stopX - 1; tmpX >= 0; tmpX--) {
            if (copyBlockList[stopY][tmpX] == copyBlockList[stopY][stopX]) {
                xList.add(new Block(tmpX, stopY, copyBlockList[stopY][tmpX]));
            } else {
                break;
            }
        }
        for (int tmpY = stopY + 1; tmpY < copyBlockList.length; tmpY++) {
            if (copyBlockList[tmpY][stopX] == copyBlockList[stopY][stopX]) {
                yList.add(new Block(stopX, tmpY, copyBlockList[tmpY][stopX]));
            } else {
                break;
            }
        }
        for (int tmpY = stopY - 1; tmpY >= 0; tmpY--) {
            if (copyBlockList[tmpY][stopX] == copyBlockList[stopY][stopX]) {
                yList.add(new Block(stopX, tmpY, copyBlockList[tmpY][stopX]));
            } else {
                break;
            }
        }
        if (xList.size() < 2 && yList.size() < 2) return new ArrayList<>();
        else if (xList.size() >= 2 && yList.size() >= 2) {
            xList.addAll(yList);
            return xList;
        } else {
            return xList.size() >= 2 ? xList : yList;
        }
    }

    /**
     * 是否存在格子
     */
    private static boolean isXyExist(int[][] blockList, int x, int y) {
        return x >= 0 && y >= 0 &&
                y < blockList.length && x < blockList[y].length;
    }

    /**
     * 重排
     */
    public static void rearrange(int[][] blockList) {
        List<Integer> list = new ArrayList<>();
        for (int y = 0; y < blockList.length; y++) {
            for (int x = 0; x < blockList[y].length; x++) {
                list.add(blockList[y][x]);
            }
        }
        Random random = new Random();
        for (int y = 0; y < blockList.length; y++) {
            for (int x = 0; x < blockList[y].length; x++) {
                int index = random.nextInt(list.size());
                blockList[y][x] = list.get(index);
                list.remove(index);
            }
        }
    }


    /**
     * 复制一份格子数据
     */
    public static int[][] getCopyBlockList(int[][] list) {
        int[][] result = new int[list.length][];
        for (int i = 0; i < list.length; i++) {
            result[i] = list[i].clone();
        }
        return result;
    }

    /**
     * 复制一份订单
     */
    public static Order getCopyOrder(Order order) {
        if(order == null){
            return null;
        }
        Order tmpOrder = new Order();
        tmpOrder.setoId(order.getoId());
        tmpOrder.setStep(order.getStep());
        tmpOrder.setMaxStep(order.getMaxStep());

        Map<Integer, OrderProg> progMap = new ConcurrentHashMap<>();
        for (OrderProg orderProg : order.getProgMap().values()) {
            progMap.put(orderProg.getbId(), new OrderProg(orderProg.getbId(), orderProg.getNeed(), orderProg.getCur()));
        }
        tmpOrder.setProgMap(progMap);

        tmpOrder.setReward(order.getReward());
        return tmpOrder;
    }


    /**
     * 获取随机订单ID
     */
    public static int getRandomOrderId(int multi, IConfig config) {
        List<Integer> idList;
        List<Integer> weightList;
        int index;

        // 随机订单
        idList = new ArrayList<>();
        weightList = new ArrayList<>();
        for (IOrderConfig orderConfig : config.getOrderConfigMap().values()) {
            if (orderConfig.getMulti() == 0 && multi == 1
                    || orderConfig.getMulti() == 1 && multi == 8
                    || orderConfig.getMulti() == 2 && multi == 16) {
                idList.add(orderConfig.getOrderId());
                weightList.add(orderConfig.getWeight());
            }
        }
        index = RandomHelper.getRandomIndexByWeight(weightList);
        IOrderConfig orderConfig = config.getOrderConfigMap().get(idList.get(index));

        return orderConfig.getOrderId();
    }

    /**
     * 补充（修复）后续订单数据
     */
    public static void checkOrderIdList(List<Integer> orderIdList, int multi, IConfig config) {
        // 有问题的删了
        Map<Integer, ? extends IOrderConfig> configMap = config.getOrderConfigMap();
        for (int i = orderIdList.size() - 1; i >= 0; i--) {
            if (i > 2 || !configMap.containsKey(orderIdList.get(i))) {
                orderIdList.remove(i);
            }
        }
        // 少的加上去
        for (int i = orderIdList.size(); i <= 2; i++) {
            orderIdList.add(getRandomOrderId(multi, config));
        }
    }

    /**
     * 判断订单状态
     *
     * @return 1进行中，2已完成，3失败
     */
    public static int checkOrderStatus(Order copyOrder) {
        boolean finish = true;
        for (OrderProg orderProg : copyOrder.getProgMap().values()) {
            if (orderProg.getCur() < orderProg.getNeed()) {
                finish = false;
                break;
            }
        }

        boolean stepMax = copyOrder.getStep() >= copyOrder.getMaxStep();

        if (stepMax) {
            return finish ? 2 : 3;
        } else {
            return finish ? 2 : 1;
        }
    }

    /**
     * 创建特定订单
     */
    public static Order createOrder(int orderId, IConfig config) {
        // 获取配置
        IOrderConfig orderConfig = config.getOrderConfigMap().get(orderId);

        Order order = new Order();
        order.setoId(orderConfig.getOrderId());
        order.setStep(0);
        order.setMaxStep(orderConfig.getMaxTimes());

        Map<Integer, OrderProg> progMap = new ConcurrentHashMap<>();
        List<Integer> numList = orderConfig.getNumList();
        List<Integer> blockList = orderConfig.getBlockList();
        for (int i = 0; i < numList.size(); i++) {
            progMap.put(blockList.get(i), new OrderProg(blockList.get(i), numList.get(i), 0));
        }
        order.setProgMap(progMap);

        order.setReward(orderConfig.getReward());

        return order;
    }

    /**
     * 计算第x轮的格子积分（x从1开始）
     */
    public static long calBlockScore(int round, int multi, IConfig config) {
        // 基础积分
        BigDecimal baseScore = BigDecimal.valueOf(config.getEliminateScoreList().get(multi == 16 ? 2 : multi == 8 ? 1 : 0));
        // 放大倍数
        int scoreAdd;
        Map<Integer, ? extends IScoreConfig> scoreConfigMap = config.getScoreConfigMap();
        if (scoreConfigMap.containsKey(round)) {
            scoreAdd = scoreConfigMap.get(round).getScoreAdd();
        } else {
            // 没有配置的话，就取最大值
            int maxRound = -1;
            for (IScoreConfig scoreConfig : scoreConfigMap.values()) {
                if (scoreConfig.getContinuousNum() > maxRound) maxRound = scoreConfig.getContinuousNum();
            }
            scoreAdd = scoreConfigMap.get(maxRound).getScoreAdd();
        }
        // 结果
        return baseScore.multiply(BigDecimal.valueOf(1000 + scoreAdd)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).longValue();
    }
}
